home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / Cache / Container.php < prev    next >
PHP Script  |  2004-10-01  |  14KB  |  456 lines

  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PEAR :: Cache                                                        |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 1997-2003 The PHP Group                                |
  6. // +----------------------------------------------------------------------+
  7. // | This source file is subject to version 2.0 of the PHP license,       |
  8. // | that is bundled with this package in the file LICENSE, and is        |
  9. // | available at through the world-wide-web at                           |
  10. // | http://www.php.net/license/2_02.txt.                                 |
  11. // | If you did not receive a copy of the PHP license and are unable to   |
  12. // | obtain it through the world-wide-web, please send a note to          |
  13. // | license@php.net so we can mail you a copy immediately.               |
  14. // +----------------------------------------------------------------------+
  15. // | Authors: Ulf Wendel <ulf.wendel@phpdoc.de>                           |
  16. // |          Sebastian Bergmann <sb@sebastian-bergmann.de>               |
  17. // |          Christian Stocker <chregu@phant.ch>                         |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: Container.php,v 1.4 2003/01/04 11:54:45 mj Exp $
  21.  
  22. require_once 'Cache/Error.php';
  23.  
  24. /**
  25. * Common base class of all cache storage container.
  26. * To speed up things we do a preload you should know about, otherwise it might 
  27. * play you a trick. The Cache controller classes (Cache/Cache, Cache/Output, ...)
  28. * usually do something like is (isCached($id) && !isExpired($id)) return $container->load($id).
  29. * if you implement isCached(), isExpired() and load() straight ahead, each of this 
  30. * functions will result in a storage medium (db, file,...) access. This generates too much load. 
  31. * Now, a simple speculative preload should saves time in most cases. Whenever 
  32. * one of the mentioned methods is invoked we preload the cached dataset into class variables.
  33. * That means that we have only one storage medium access for the sequence
  34. *  (isCached($id) && !isExpired($id)) return $container->load($id).
  35. * The bad thing is that the preloaded data might be outdated meanwhile, which is 
  36. * unlikely but for you power users, be warned. If you do not want the preload 
  37. * you should switch it off by setting the class variable $preload to false. Anyway, this is 
  38. * not recommended!
  39. * @author   Ulf Wendel <ulf.wendel@phpdoc.de>
  40. * @version  $Id: Container.php,v 1.4 2003/01/04 11:54:45 mj Exp $
  41. * @package  Cache
  42. * @access   public
  43. * @abstract
  44. */
  45. class Cache_Container {
  46.  
  47.     /**
  48.     * Flag indicating wheter to preload datasets.
  49.     *
  50.     * See the class description for more details.
  51.     *
  52.     * @var  boolean
  53.     */
  54.     var $preload = true;
  55.  
  56.     /**
  57.     * ID of a preloaded dataset
  58.     *
  59.     * @var  string
  60.     */
  61.     var $id = '';
  62.  
  63.     /**
  64.     * Cache group of a preloaded dataset
  65.     *
  66.     * @var  string
  67.     */
  68.     var $group = '';
  69.  
  70.     /**
  71.     * Expiration timestamp of a preloaded dataset.
  72.     * 
  73.     * @var  integer 0 means never, endless
  74.     */
  75.     var $expires = 0;
  76.  
  77.     /**
  78.     * Value of a preloaded dataset.
  79.     * 
  80.     * @var  string
  81.     */
  82.     var $cachedata = '';
  83.  
  84.     /**
  85.     * Preloaded userdata field.
  86.     * 
  87.     * @var  string
  88.     */
  89.     var $userdata = '';
  90.  
  91.     /**
  92.     * Flag indicating that the dataset requested for preloading is unknown.
  93.     *  
  94.     * @var  boolean
  95.     */
  96.     var $unknown = true;
  97.  
  98.     /**
  99.     * Encoding mode for cache data: base64 or addslashes() (slash).
  100.     *
  101.     * @var  string  base64 or slash
  102.     */
  103.     var $encoding_mode = 'base64';
  104.     
  105.     /**
  106.     * Highwater mark - maximum space required by all cache entries.
  107.     * 
  108.     * Whenever the garbage collection runs it checks the amount of space
  109.     * required by all cache entries. If it's more than n (highwater) bytes
  110.     * the garbage collection deletes as many entries as necessary to reach the
  111.     * lowwater mark. 
  112.     * 
  113.     * @var  int
  114.     * @see  lowwater
  115.     */
  116.     var $highwater = 2048000; 
  117.     
  118.     
  119.     /**
  120.     * Lowwater mark
  121.     *
  122.     * @var  int
  123.     * @see  highwater
  124.     */
  125.     var $lowwater = 1536000;
  126.     
  127.     
  128.     /**
  129.     * Options that can be set in every derived class using it's constructor.
  130.     * 
  131.     * @var  array
  132.     */
  133.     var $allowed_options = array('encoding_mode', 'highwater', 'lowwater');
  134.     
  135.     
  136.     /**
  137.     * Loads a dataset from the cache.
  138.     * 
  139.     * @param    string  dataset ID
  140.     * @param    string  cache group
  141.     * @return   mixed   dataset value or NULL on failure
  142.     * @access   public
  143.     */
  144.     function load($id, $group) {
  145.         if ($this->preload) {
  146.             if ($this->id != $id || $this->group != $group)
  147.                 $this->preload($id, $group);
  148.  
  149.             return $this->cachedata;
  150.         } else {
  151.             list( , $data, ) = $this->fetch($id, $group);
  152.             return $data;
  153.         }
  154.     } // end func load
  155.  
  156.     /**
  157.     * Returns the userdata field of a cached data set.
  158.     *
  159.     * @param    string  dataset ID
  160.     * @param    string  cache group
  161.     * @return   string  userdata
  162.     * @access   public
  163.     */
  164.     function getUserdata($id, $group) {
  165.         if ($this->preload) {
  166.             if ($this->id != $id || $this->group != $group)
  167.                 $this->preload($id, $group);
  168.                 
  169.             return $this->userdata;
  170.         } else {
  171.             list( , , $userdata) = $this->fetch($id, $group);
  172.             return $userdata;
  173.         }
  174.     } // end func getUserdata
  175.  
  176.     /**
  177.     * Checks if a dataset is expired.
  178.     * 
  179.     * @param    string  dataset ID
  180.     * @param    string  cache group
  181.     * @param    integer maximum age timestamp
  182.     * @return   boolean 
  183.     * @access   public
  184.     */
  185.     function isExpired($id, $group, $max_age) {
  186.         if ($this->preload) {
  187.           if ($this->id != $id || $this->group != $group)
  188.             $this->preload($id, $group);
  189.           
  190.           if ($this->unknown)
  191.             return false;
  192.         } else {
  193.             // check if at all it is cached
  194.             if (!$this->isCached($id, $group))
  195.                 return false;
  196.                 
  197.             // I'm lazy...
  198.             list($this->expires, , ) = $this->fetch($id, $group);
  199.         }
  200.  
  201.         // endless
  202.         if (0 == $this->expires)
  203.             return false;
  204.  
  205.         // you feel fine, Ulf?
  206.         if ($expired  = ($this->expires <= time() || ($max_age && ($this->expires <= $max_age))) ) {
  207.  
  208.            $this->remove($id, $group);
  209.            $this->flushPreload();
  210.         }
  211.         return $expired;
  212.     } // end func isExpired
  213.  
  214.     /**
  215.     * Checks if a dataset is cached.
  216.     *
  217.     * @param    string  dataset ID
  218.     * @param    string  cache group
  219.     * @return   boolean
  220.     */
  221.     function isCached($id, $group) {
  222.         if ($this->preload) {
  223.             if ($this->id != $id || $this->group != $group)
  224.                 $this->preload($id, $group);
  225.  
  226.             return !($this->unknown);
  227.         } else {
  228.             return $this->idExists($id, $group);
  229.         }
  230.     } // end func isCached
  231.  
  232.     //
  233.     // abstract methods
  234.     //
  235.  
  236.     /**
  237.     * Fetches a dataset from the storage medium.
  238.     *
  239.     * @param    string  dataset ID
  240.     * @param    string  cache group
  241.     * @return   array   format: [expire date, cached data, user data]
  242.     * @throws   Cache_Error
  243.     * @abstract
  244.     */
  245.     function fetch($id, $group) {
  246.         return array(NULL, NULL, NULL);
  247.     } // end func fetch
  248.  
  249.     /**
  250.     * Stores a dataset.
  251.     * 
  252.     * @param    string  dataset ID
  253.     * @param    mixed   data to store
  254.     * @param    mixed   userdefined expire date
  255.     * @param    string  cache group
  256.     * @param    string  additional userdefined data
  257.     * @return   boolean
  258.     * @throws   Cache_Error
  259.     * @access   public
  260.     * @abstract
  261.     */
  262.     function save($id, $data, $expire, $group, $userdata) {
  263.         // QUESTION: Should we update the preload buffer instead?
  264.         // Don't think so as the sequence save()/load() is unlikely.
  265.         $this->flushPreload($id, $group);
  266.  
  267.         return NULL;
  268.     } // end func save
  269.  
  270.     /**
  271.     * Removes a dataset.
  272.     * 
  273.     * @param    string  dataset ID
  274.     * @param    string  cache group
  275.     * @return   boolean  
  276.     * @access   public
  277.     * @abstract
  278.     */     
  279.     function remove($id, $group) {
  280.         $this->flushPreload($id, $group);
  281.         return NULL;
  282.     } // end func remove
  283.  
  284.     /**
  285.     * Flushes the cache - removes all caches datasets from the cache.
  286.     * 
  287.     * @param    string      If a cache group is given only the group will be flushed
  288.     * @return   integer     Number of removed datasets, -1 on failure
  289.     * @access   public
  290.     * @abstract
  291.     */
  292.     function flush($group) {
  293.         $this->flushPreload();
  294.         return NULL;
  295.     } // end func flush
  296.  
  297.     /**
  298.     * Checks if a dataset exists.
  299.     * 
  300.     * @param    string  dataset ID
  301.     * @param    string  cache group
  302.     * @return   boolean 
  303.     * @access   public
  304.     * @abstract
  305.     */
  306.     function idExists($id, $group) {
  307.         return NULL;
  308.     } // end func idExists
  309.  
  310.     /**
  311.     * Starts the garbage collection.
  312.     * 
  313.     * @access   public
  314.     * @abstract
  315.     */
  316.     function garbageCollection() {
  317.         $this->flushPreload();
  318.     } // end func garbageCollection
  319.  
  320.     /**
  321.     * Does a speculative preload of a dataset
  322.     *
  323.     * @param    string  dataset ID
  324.     * @param    string  cache group
  325.     * @return   boolean
  326.     */ 
  327.     function preload($id, $group) {
  328.         // whatever happens, remember the preloaded ID
  329.         $this->id = $id;
  330.         $this->group = $group;        
  331.  
  332.         list($this->expires, $this->cachedata, $this->userdata) = $this->fetch($id, $group);
  333.  
  334.         if (NULL === $this->expires) {
  335.             // Uuups, unknown ID
  336.             $this->flushPreload();
  337.  
  338.             return false;
  339.         }
  340.  
  341.         $this->unknown = false;
  342.  
  343.         return true;
  344.     } // end func preload
  345.  
  346.     /**
  347.     * Flushes the internal preload buffer.
  348.     *
  349.     * save(), remove() and flush() must call this method
  350.     * to preevent differences between the preloaded values and 
  351.     * the real cache contents.
  352.     *
  353.     * @param    string  dataset ID, if left out the preloaded values will be flushed. 
  354.     *                   If given the preloaded values will only be flushed if they are
  355.     *                   equal to the given id and group
  356.     * @param    string  cache group
  357.     * @see  preload()
  358.     */
  359.     function flushPreload($id = '', $group = 'default') {
  360.         if (!$id || ($this->id == $id && $this->group == $group)) {
  361.             // clear the internal preload values
  362.             $this->id = '';
  363.             $this->group = '';
  364.             $this->cachedata = '';
  365.             $this->userdata = '';
  366.             $this->expires = -1;
  367.             $this->unknown = true;
  368.         }
  369.     } // end func flushPreload
  370.  
  371.     /**
  372.     * Imports the requested datafields as object variables if allowed
  373.     * 
  374.     * @param    array   List of fields to be imported as object variables
  375.     * @param    array   List of allowed datafields
  376.     */
  377.     function setOptions($requested, $allowed) {
  378.         foreach ($allowed as $k => $field)
  379.             if (isset($requested[$field]))
  380.                 $this->$field = $requested[$field];
  381.                 
  382.     } // end func setOptions
  383.  
  384.     /**
  385.     * Encodes the data for the storage container.
  386.     * 
  387.     * @var  mixed data to encode
  388.     */
  389.     function encode($data) {
  390.         if ('base64' == $this->encoding_mode) 
  391.             return base64_encode(serialize($data));
  392.         else 
  393.             return serialize($data);
  394.     } // end func encode
  395.  
  396.     
  397.     /**
  398.     * Decodes the data from the storage container.
  399.     * 
  400.     * @var  mixed
  401.     */
  402.     function decode($data) {
  403.         if ('base64' == $this->encoding_mode)
  404.             return unserialize(base64_decode($data));
  405.         else
  406.             return unserialize($data);
  407.     } // end func decode
  408.  
  409.     
  410.     /**
  411.     * Translates human readable/relative times in unixtime
  412.     *
  413.     * @param  mixed   can be in the following formats:
  414.     *               human readable          : yyyymmddhhmm[ss]] eg: 20010308095100
  415.     *               relative in seconds (1) : +xx              eg: +10
  416.     *               relative in seconds (2) : x <  946681200   eg: 10
  417.     *               absolute unixtime       : x < 2147483648   eg: 2147483648
  418.     *               see comments in code for details
  419.     * @return integer unix timestamp
  420.     */
  421.     function getExpiresAbsolute($expires)
  422.     {
  423.         if (!$expires)
  424.             return 0;
  425.         //for api-compatibility, one has not to provide a "+",
  426.         // if integer is < 946681200 (= Jan 01 2000 00:00:00)
  427.         if ('+' == $expires[0] || $expires < 946681200)
  428.         {
  429.             return(time() + $expires);
  430.         }
  431.         //if integer is < 100000000000 (= in 3140 years),
  432.         // it must be an absolut unixtime
  433.         // (since the "human readable" definition asks for a higher number)
  434.         elseif ($expires < 100000000000)
  435.         {
  436.             return $expires;
  437.         }
  438.         // else it's "human readable";
  439.         else
  440.         {
  441.             $year = substr($expires, 0, 4);
  442.             $month = substr($expires, 4, 2);
  443.             $day = substr($expires, 6, 2);
  444.             $hour = substr($expires, 8, 2);
  445.             $minute = substr($expires, 10, 2);
  446.             $second = substr($expires, 12, 2);
  447.             return mktime($hour, $minute, $second, $month, $day, $year);
  448.         }
  449.         
  450.     } // end func getExpireAbsolute
  451.     
  452. } // end class Container
  453. ?>
  454.